package info.ask4research.web.validator;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sun.org.apache.xpath.internal.XPathAPI;


public class LearningDesignValidator {

	
	
	public LearningDesignValidator(){}
	
	private HashMap<String,String> startExit = new HashMap<String, String>();
	private HashMap<String,String> activities = new HashMap<String, String>();
	private HashMap<String,String> connections = new HashMap<String, String>();
	private List<String> connectionsSource = new ArrayList<String>();
	private List<String> connectionsTarget = new ArrayList<String>();
	
	private List<String> activityName = new ArrayList<String>();
	private List<String> activityId = new ArrayList<String>();
	
	private boolean containsSplit=false;
	private int countTwoToOne = 0;
	private int countOneToTwo = 0;
	
	public InputStream fromStringToInpuStream(String str)
	{
		InputStream is = new ByteArrayInputStream(str.getBytes());
		return is;
	}
	
	public String analiseStructure(String graph) throws Exception{
		Map<String,Object> modelMap = new HashMap<String,Object>(3);
		Document doc = null;
		HashMap<Integer, Object> hash = new HashMap<Integer, Object>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		doc = db.parse(fromStringToInpuStream(graph));
		startNode(doc);
		exitNode(doc);
		activityNode(doc);
		String validationRules = "";
		if(countTwoToOne != countOneToTwo){
			validationRules+="Split and Merge nodes are not Equal<br/>";
		}
		if(startExit.size() < 2){
			System.out.println("startExit.size()"+ startExit.size());
			validationRules+="Missing Start or Exit Node!<br/>";
		}
		
		return validationRules;
		
	}
	/**
	 * @param args
	 * @throws ParserConfigurationException 
	 * @throws IOException 
	 * @throws SAXException 
	 * @throws TransformerException 
	 */
	public HashMap<Object, Object> getStructure(String graph) throws ParserConfigurationException, SAXException, IOException, TransformerException {
		Document doc = null;
		HashMap<Object, Object> hash = new HashMap<Object, Object>();
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		doc = db.parse(fromStringToInpuStream(graph));

		startNode(doc);
		exitNode(doc);
		activityNode(doc);
		
		connectionsNode(doc);

		List<String> orderArray = new ArrayList<String>();
		//make it serialized

		orderArray.add(startExit.get("Start"));
		String start = startExit.get("Start");
		hash.put("containsSplit", containsSplit);
		
		if(containsSplit){
			
			//String startTarget = connections.get(start);
			
				for(int k = 0; k<connectionsSource.size(); k++){
					if(start.equals(connectionsSource.get(k))){
							if(activities.get(connectionsTarget.get(k)).equals("Activity") || 
									activities.get(connectionsTarget.get(k)).equals("SupportActivity")){
								
								orderArray.add(connectionsTarget.get(k));
								start=connectionsTarget.get(k);
							} else if(activities.get(connectionsTarget.get(k)).equals("OneToTwo")){
								orderArray.add(connectionsTarget.get(k));
								start=connectionsTarget.get(k);
								StringBuilder actsAfterSplit = new StringBuilder();
								for(int con = 0; con<connectionsSource.size(); con++){
									if(start.equals(connectionsSource.get(con))){
										actsAfterSplit.append(":"+connectionsTarget.get(con)); 
									}
								}
								orderArray.add(actsAfterSplit.substring(1));
								String [] acts = actsAfterSplit.toString().split(":");
								start=connectionsTarget.get(k);
								for(int m = 0; m<connectionsSource.size(); m++){
									if(acts[1].equals(connectionsSource.get(m))){
										String twoToOne = connectionsTarget.get(m);
										orderArray.add(twoToOne);
										start=connectionsTarget.get(m);
									}
								}
								
						}
					}
					
				}
			orderArray.add(startExit.get("Exit"));
		}
		else{
			for(int k = 0; k<activities.size()-1; k++){
						start = connections.get(start);
						orderArray.add(start);
			}
		}
		
		hash.put("data", orderArray);
		for(int i =0; i<orderArray.size();i++){
			System.out.println(i+" "+orderArray.get(i));
		}
		return hash;
	}
	
	
	private void activityNode(Document doc) throws TransformerException {
		String activityXPath = "form/Activity";
		NodeList activityNodeList = XPathAPI.selectNodeList(doc, activityXPath);
		for(int i=0;i<activityNodeList.getLength(); i++){
			Node node = activityNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");
			activityName.add("Activity");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "Activity");
		}
		
		String supportActivityXPath = "form/SupportActivity";
		NodeList supportActivityNodeList = XPathAPI.selectNodeList(doc, supportActivityXPath);
		for(int i=0;i<supportActivityNodeList.getLength(); i++){
			Node node = supportActivityNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");
			
			activityName.add("SupportActivity");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "SupportActivity");
		}
		
		String twoToOneXPath = "form/TwoToOne";
		NodeList twoToOneNodeList = XPathAPI.selectNodeList(doc, twoToOneXPath);
		for(int i=0;i<twoToOneNodeList.getLength(); i++){
			Node node = twoToOneNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");
			containsSplit = true;
			countTwoToOne++;
			activityName.add("TwoToOne");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "TwoToOne");
		}
		
		String oneToTwoXPath = "form/OneToTwo";
		NodeList oneToTwoNodeList = XPathAPI.selectNodeList(doc, oneToTwoXPath);
		for(int i=0;i<oneToTwoNodeList.getLength(); i++){
			Node node = oneToTwoNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");
			containsSplit =true;
			countOneToTwo++;
			activityName.add("OneToTwo");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "OneToTwo");
		}
		
		String startXPath = "form/Start";
		NodeList startNodeList = XPathAPI.selectNodeList(doc, startXPath);
		for(int i=0;i<startNodeList.getLength(); i++){
			Node node = startNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");

			activityName.add("Start");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "Start");
		}
		
		String exitXPath = "form/Exit";
		NodeList exitNodeList = XPathAPI.selectNodeList(doc, exitXPath);
		for(int i=0;i<exitNodeList.getLength(); i++){
			Node node = exitNodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node startId = namedNodeMap.getNamedItem("id");

			activityName.add("Exit");
			activityId.add(startId.getNodeValue());
			activities.put(startId.getNodeValue(), "Exit");
		}
	}
	
	private void connectionsNode(Document doc) throws TransformerException {
		String startXPath = "form/Connection";
		NodeList nodeList = XPathAPI.selectNodeList(doc, startXPath);
		
		for(int i=0;i<nodeList.getLength(); i++){
			Node node = nodeList.item(i);
			NamedNodeMap namedNodeMap = node.getAttributes();
			Node sourceParentNodeId = namedNodeMap.getNamedItem("sourceParentNodeId");
			connectionsSource.add(sourceParentNodeId.getNodeValue());
			Node targetParentNodeId = namedNodeMap.getNamedItem("targetParentNodeId");
			connectionsTarget.add(targetParentNodeId.getNodeValue());
			connections.put(sourceParentNodeId.getNodeValue(), targetParentNodeId.getNodeValue());
		}
	}

	private void startNode(Document doc) throws TransformerException {
		String startXPath = "form/Start";
		NodeList nodeList = XPathAPI.selectNodeList(doc, startXPath);
		Node node = nodeList.item(0);
		NamedNodeMap namedNodeMap = node.getAttributes();
		Node startId = namedNodeMap.getNamedItem("id");
		
		startExit.put("Start", startId.getNodeValue());
	}
	
	private void exitNode(Document doc) throws TransformerException {
		String startXPath = "form/Exit";
		NodeList nodeList = XPathAPI.selectNodeList(doc, startXPath);
		Node node = nodeList.item(0);
		NamedNodeMap namedNodeMap = node.getAttributes();
		Node startId = namedNodeMap.getNamedItem("id");
		
		startExit.put("Exit", startId.getNodeValue());
	}
}
